﻿using Microsoft.Extensions.DependencyInjection;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace zijian666.DI
{
    /// <summary>
    /// 命名服务扩展方法
    /// </summary>
    public static class NamedServiceExtensions
    {
        static IServiceCollection FluentAdd(this IServiceCollection services, ServiceDescriptor descriptor)
        {
            services?.Add(descriptor);
            return services!;
        }

        #region Delegate

        /// <summary>
        /// 添加命名委托
        /// </summary>
        /// <typeparam name="T">委托类型</typeparam>
        /// <param name="services">服务集合</param>
        /// <param name="name">服务名称</param>
        /// <param name="delegate">委托</param>
        /// <returns></returns>
        public static IServiceCollection AddNamedDelegate<T>(this IServiceCollection services, string name, T @delegate)
             where T : class
        {
            if (@delegate is Delegate dele)
            {
                return services.AddNamedDelegate(name, dele.Method);
            }
            throw new ArgumentException(nameof(@delegate) + " 不是一个有效的委托类型");
        }

        /// <summary>
        /// 添加命名委托
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="name">服务名称</param>
        /// <param name="method">方法</param>
        /// <returns></returns>
        public static IServiceCollection AddNamedDelegate(this IServiceCollection services, string name, MethodInfo method) => services.AddNamedSingleton(name, method);

        /// <summary>
        /// 获取命名委托
        /// </summary>
        /// <typeparam name="T">委托类型</typeparam>
        /// <param name="provider">服务提供程序</param>
        /// <param name="name">服务名称</param>
        /// <returns></returns>
        public static T? GetNamedDelegate<T>(this IServiceProvider provider, string name) where T : class =>
            DelegateServiceHelper.ConvertDelegate<T>(provider.GetNamedService<MethodInfo>(name));

        /// <summary>
        /// 获取命名委托集合
        /// </summary>
        /// <typeparam name="T">委托类型</typeparam>
        /// <param name="provider">服务提供程序</param>
        /// <param name="name">服务名称</param>
        /// <returns></returns>
        public static IEnumerable<T> GetNamedDelegates<T>(this IServiceProvider provider, string name) where T : class =>
            provider.GetNamedServices<MethodInfo>(name).Select(DelegateServiceHelper.ConvertDelegate<T>).Where(x => x is not null).Select(x => x!);

        #endregion

        #region Scoped
        /// <summary>
        /// 添加命名服务
        /// </summary>
        /// <typeparam name="TService">服务类型</typeparam>
        /// <param name="services">服务集合</param>
        /// <param name="name">服务名称</param>
        public static IServiceCollection AddNamedScoped<TService>(this IServiceCollection services, string name)
          where TService : class =>
            services.FluentAdd(ServiceDescriptor.Scoped(NamedType.Get(name, typeof(TService)), typeof(TService)));
        /// <summary>
        /// 添加命名服务
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="name">服务名称</param>
        /// <param name="implementationFactory">用于创建服务实例的工厂</param>
        public static IServiceCollection AddNamedScoped(this IServiceCollection services, string name, Func<IServiceProvider, object> implementationFactory) =>
            services.FluentAdd(ServiceDescriptor.Scoped(NamedType.Get(name, null), implementationFactory));
        /// <summary>
        /// 添加命名服务
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="name">服务名称</param>
        /// <param name="implementationType">实现服务的 <seealso cref="Type"/></param>
        public static IServiceCollection AddNamedScoped(this IServiceCollection services, string name, Type implementationType) =>
            services.FluentAdd(ServiceDescriptor.Scoped(NamedType.Get(name, implementationType), implementationType));
        #endregion

        #region Singleton
        /// <summary>
        /// 添加命名服务
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="name">服务名称</param>
        public static IServiceCollection AddNamedSingleton<TService>(this IServiceCollection services, string name)
            where TService : class =>
            services.FluentAdd(ServiceDescriptor.Singleton(NamedType.Get(name, typeof(TService)), typeof(TService)));

        /// <summary>
        /// 添加命名服务
        /// <param name="services">服务集合</param>
        /// </summary>
        /// <param name="name">服务名称</param>
        /// <param name="implementationFactory">用于创建服务实例的工厂</param>
        public static IServiceCollection AddNamedSingleton(this IServiceCollection services, string name, Func<IServiceProvider, object> implementationFactory) =>
            services.FluentAdd(ServiceDescriptor.Singleton(NamedType.Get(name, null), implementationFactory));

        /// <summary>
        /// 添加命名服务
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="name">服务名称</param>
        /// <param name="implementationType">实现服务的 <seealso cref="Type"/></param>
        public static IServiceCollection AddNamedSingleton(this IServiceCollection services, string name, Type implementationType) =>
            services.FluentAdd(ServiceDescriptor.Singleton(NamedType.Get(name, implementationType), implementationType));

        /// <summary>
        /// 添加命名服务
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="name">服务名称</param>
        /// <param name="implementationInstance">实现服务的实例</param>
        public static IServiceCollection AddNamedSingleton<TService>(this IServiceCollection services, string name, TService implementationInstance)
            where TService : notnull =>
            services.FluentAdd(ServiceDescriptor.Singleton(NamedType.Get(name, typeof(TService)), implementationInstance));

        #endregion

        #region Transient
        /// <summary>
        /// 添加命名服务
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="name">服务名称</param>
        public static IServiceCollection AddNamedTransient<TService>(this IServiceCollection services, string name) =>
            services.FluentAdd(ServiceDescriptor.Transient(NamedType.Get(name, typeof(TService)), typeof(TService)));
        /// <summary>
        /// 添加命名服务
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="name">服务名称</param>
        /// <param name="implementationFactory">用于创建服务实例的工厂</param>
        public static IServiceCollection AddNamedTransient(this IServiceCollection services, string name, Func<IServiceProvider, object> implementationFactory) =>
            services.FluentAdd(ServiceDescriptor.Transient(NamedType.Get(name, null), implementationFactory));
        /// <summary>
        /// 添加命名服务
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="name">服务名称</param>
        /// <param name="implementationType">实现服务的 <seealso cref="Type"/></param>
        public static IServiceCollection AddNamedTransient(this IServiceCollection services, string name, Type implementationType) =>
            services.FluentAdd(ServiceDescriptor.Transient(NamedType.Get(name, implementationType), implementationType));
        #endregion

        #region GetService

        /// <summary>
        /// 获取命名服务
        /// </summary>
        /// <param name="provider">服务提供程序</param>
        /// <param name="name">服务名称</param>
        public static object? GetNamedService(this IServiceProvider provider, string name) =>
            provider.GetService(NamedType.Get(name));
        /// <summary>
        /// 获取命名服务
        /// </summary>
        /// <param name="provider">服务提供程序</param>
        /// <param name="name">服务名称</param>
        public static object GetRequiredNamedService(this IServiceProvider provider, string name) =>
            provider.GetRequiredService(NamedType.Get(name));
        /// <summary>
        /// 获取命名服务
        /// </summary>
        /// <param name="provider">服务提供程序</param>
        /// <param name="name">服务名称</param>
        /// <param name="serviceType">服务类型</param>
        public static object GetRequiredNamedService(this IServiceProvider provider, string name, Type serviceType) =>
            provider.GetRequiredService(NamedType.Get(name, serviceType));
        /// <summary>
        /// 获取命名服务
        /// </summary>
        /// <param name="provider">服务提供程序</param>
        /// <param name="name">服务名称</param>
        public static T GetRequiredNamedService<T>(this IServiceProvider provider, string name)
             where T : class
        {
            var service = provider.GetNamedService<T>(name) ?? throw new InvalidOperationException("There is no service of type serviceType.");
            return service;
        }

        /// <summary>
        /// 获取命名服务
        /// </summary>
        /// <param name="provider">服务提供程序</param>
        /// <param name="name">服务名称</param>
        public static T? GetNamedService<T>(this IServiceProvider provider, string name) where T : class =>
            provider.GetService(NamedType.Get(name)) is T t ? t : default;

        /// <summary>
        /// 获取命名服务
        /// </summary>
        /// <param name="provider">服务提供程序</param>
        /// <param name="name">服务名称</param>
        public static IEnumerable<T> GetNamedServices<T>(this IServiceProvider provider, string name) where T : class =>
            provider.GetServices(NamedType.Get(name)).OfType<T>().ToArray();
        /// <summary>
        /// 获取命名服务
        /// </summary>
        /// <param name="provider">服务提供程序</param>
        /// <param name="name">服务名称</param>
        /// <param name="serviceType">服务类型</param>
        public static IEnumerable<object> GetNamedServices(this IServiceProvider provider, string name, Type? serviceType = null) =>
            provider.GetServices(NamedType.Get(name)).Where((serviceType ?? typeof(object)).IsInstanceOfType).Select(x => x!).ToArray();
        #endregion
    }
}
